package cn.dgiot.fd.utils;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * 日期时间工具类
 * @author
 *
 */
public class DateUtil {

    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYYMMDD = "yyyyMMdd";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String YYYY_MM_DD_HH_MM_2 = "yyyy年MM月dd日 HH:mm";
    public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
    public static final String YYYY_MM_DD_HH_2 = "yyyy/MM/dd HH";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY_MM_DD_2 = "yyyy/MM/dd";
    public static final String YYYY_MM_DD_3 = "yyyy年MM月dd日";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY = "yyyy";
    public static final String MM = "MM";
    public static final String MM_DD_HH_MM = " MM月dd日, HH:mm";
    public static final String MM_DD_1 = "MM月dd日";
    public static final String MM_DD_2 = "MM-dd";
    public static final String MM_DD_3 = "dd/MM";
    public static final String DD = "dd";
    public static final String HH_MM = "HH:mm";
    public static final String EEEE = "EEEE";

    public final static int DATE_TYPE_START = 1;
    public final static int DATE_TYPE_CURRENT = 2;
    public final static int DATE_TYPE_END = 3;
    
    public final static String MONDAY = "2";
    public final static String TUESDAY = "3";
    public final static String WEDNESDAY ="4";
    public final static String THURSDAY ="5";
    public final static String FRIDAY ="6";
    public final static String SATURDAY ="7";
    public final static String SUNDAY ="1";
    
    public final static String MONDAY_CN = "星期一";
    public final static String TUESDAY_CN = "星期二";
    public final static String WEDNESDAY_CN ="星期三";
    public final static String THURSDAY_CN ="星期四";
    public final static String FRIDAY_CN ="星期五";
    public final static String SATURDAY_CN ="星期六";
    public final static String SUNDAY_CN ="星期天";

    /**
     * 一周日期分隔符
     */
    public static final String FIRST_END_WEEK_SEPARATOR = "/";

    /**
     * @param startDate 初始日期
     * @param addDays   增加或减少天数
     * @return 新日期
     */
    public static Date addDate(Date startDate, int addDays) {
        Calendar startCalender = Calendar.getInstance();
        startCalender.setTime(startDate);
        startCalender.add(Calendar.DATE, addDays);
        return startCalender.getTime();
    }

    /**
     * @param startDate  初始日期
     * @param addMinutes 增加或减少分钟数
     * @return 新日期
     */
    public static Date addMinute(Date startDate, int addMinutes) {
        Calendar startCalender = Calendar.getInstance();
        startCalender.setTime(startDate);
        startCalender.add(Calendar.MINUTE, addMinutes);
        return startCalender.getTime();
    }

    /**
     * 间隔天数
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 天数
     */
    public static long intervalDays(Date startDate, Date endDate) {
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        return ChronoUnit.DAYS.between(startLocalDate,endLocalDate);
    }

    public static String getWeek(Date date) {
        Calendar lCompCal = Calendar.getInstance();
        lCompCal.setTime(date);
        String mWay = String.valueOf(lCompCal.get(Calendar.DAY_OF_WEEK));
        if (SUNDAY.equals(mWay)) {
            mWay = SUNDAY_CN;
        } else if (MONDAY.equals(mWay)) {
            mWay = MONDAY_CN;
        } else if (TUESDAY.equals(mWay)) {
            mWay = TUESDAY_CN;
        } else if (WEDNESDAY.equals(mWay)) {
            mWay = WEDNESDAY_CN;
        } else if (THURSDAY.equals(mWay)) {
            mWay = THURSDAY_CN;
        } else if (FRIDAY.equals(mWay)) {
            mWay = FRIDAY_CN;
        } else if (SATURDAY.equals(mWay)) {
            mWay = SATURDAY_CN;
        }
        return mWay;
    }

    public static int getWeekInt(Date date) {
        Calendar lCompCal = Calendar.getInstance();
        lCompCal.setTime(date);
        return lCompCal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取format日期格式字符串 默认yyyy-MM-dd日期格式
     *
     * @param format
     * @return String
     */
    public static String getDateString(String... format) {
        Date date = new Date();
        String lDate;
        if (format.length > 0) {
            lDate = formatDate(date, format[0]);
        } else {
            lDate = formatDate(date, YYYY_MM_DD);
        }
        return lDate;
    }

    public static Date getDateByPattern(String dateText, String pattern) throws Exception {
        if (null != dateText) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            Date lDate = null;
            try {
                lDate = sdf.parse(dateText);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw e;
            }
            return lDate;
        }
        return null;
    }

    public static String getTextByDate(Date date, String pattern) {
        if (null != date) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            String lDateText = null;
            try {
                lDateText = sdf.format(date);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            return lDateText;
        }
        return null;
    }

    public static String getRefreshTime(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy  HH:mm:ss");
        return sdf.format(date);
    }

    /**
     * 格式化日期
     *
     * @param date
     * @param format
     * @return
     */
    public static String formatDate(Date date, String format) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 格式化日期
     *
     * @param date
     * @param dateType
     * @return
     */
    public static String formatDate(Date date, int dateType) {
        SimpleDateFormat sdf;
        switch (dateType) {
            case DATE_TYPE_START:
                sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
                break;
            case DATE_TYPE_CURRENT:
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                break;
            case DATE_TYPE_END:
                sdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
                break;
            default:
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                break;
        }
        return sdf.format(date);
    }

    public static Date parseDate(String date, String format) {
        SimpleDateFormat df = new SimpleDateFormat(format);
        try {
            return df.parse(date);
        } catch (ParseException e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    public static Date parseDate(String date) {
        if (StringUtils.isEmpty(date)) {
            return null;
        }
        try {
            String format = getDateFormat(date);
            if (format == null) {
                DateFormat df = SimpleDateFormat.getDateTimeInstance();
                return df.parse(date);
            } else {
                SimpleDateFormat df = new SimpleDateFormat(format);
                return df.parse(date);
            }
        } catch (ParseException e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    public static Date parseDateExp(String date) throws ParseException {
        String format = getDateFormat(date);
        if (format == null) {
            DateFormat df = SimpleDateFormat.getDateTimeInstance();
            return df.parse(date);
        } else {
            SimpleDateFormat df = new SimpleDateFormat(format);
            return df.parse(date);
        }
    }

    /**
     * @param date
     * @return日期格式
     */
    private static String getDateFormat(String date) {
        String result = null;
        String input = date.trim();
        if (Pattern.matches("\\d{2,4}-\\d{1,2}-\\d{1,2}.*", input)) {
            result = "yyyy-MM-dd";
        } else if (Pattern.matches("\\d{1,2}-\\d{1,2}-\\d{2,4}.*", input)) {
            result = "MM-dd-yyyy";
        } else if (Pattern.matches("\\d{2,4}/\\d{1,2}/\\d{1,2}.*", input)) {
            result = "yyyy/MM/dd";
        } else if (Pattern.matches("\\d{1,2}/\\d{1,2}/\\d{2,4}.*", input)) {
            result = "MM/dd/yyyy";
        } else if (Pattern.matches("\\d{6,8}.*", input)) {
            result = "yyyyMMdd";
        }
        if (input.length() > 12) {
            if (input.length() < 17) {
                result = result + " HH:mm";
            } else {
                result = result + " HH:mm:ss";
            }
        }

        return result;
    }

    private static boolean isToday(String datetime) {
        Calendar c = Calendar.getInstance();
        Date today = c.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        datetime = datetime.trim();
        String ymd = datetime.substring(0, datetime.indexOf(" "));
        return format.format(today).equals(ymd);
    }

    private static boolean isYear(String datetime) {
        Calendar c = Calendar.getInstance();
        String nowyear = String.valueOf(c.get(Calendar.YEAR));
        datetime = datetime.trim();
        String year = datetime.substring(0, datetime.indexOf("-"));
        return nowyear.equals(year);
    }

    private static long timeDistance(Date datetime) {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.DATE, c.get(Calendar.DATE));
        Date today = c.getTime();
        long dis = today.getTime() - datetime.getTime();
        if (dis < 0) {
            return 0;
        } else {
            return dis;
        }
    }

    public static String getRoleTime(String datetime) {
        try {
            SimpleDateFormat lSdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
            Calendar lCompCal = Calendar.getInstance();
            lCompCal.setTime(lSdf.parse(datetime));
            DecimalFormat df = new DecimalFormat("00");
            if (isToday(datetime)) {
                long timeDis = timeDistance(lSdf.parse(datetime)) / 1000;
                if (timeDis < 60) {
                    return timeDis + "秒前";
                } else if (timeDis < 60 * 60) {
                    return timeDis / 60 + "分钟前";
                } else {
                    return /* "今天 " + */lCompCal.get(Calendar.HOUR_OF_DAY) + ":" + df.format(lCompCal.get(Calendar.MINUTE));
                }
            } else if (isYear(datetime)) {
                return (lCompCal.get(Calendar.MONTH) + 1) + "-" + lCompCal.get(Calendar.DAY_OF_MONTH) + " " + lCompCal.get(Calendar.HOUR_OF_DAY) + ":"
                        + df.format(lCompCal.get(Calendar.MINUTE));
            } else {
                return lCompCal.get(Calendar.YEAR) + "-" + (lCompCal.get(Calendar.MONTH) + 1) + "-" + lCompCal.get(Calendar.DAY_OF_MONTH) + " "
                        + lCompCal.get(Calendar.HOUR_OF_DAY) + ":" + df.format(lCompCal.get(Calendar.MINUTE));
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
        }
        return datetime;
    }

    /**
     * 获取某天是周几
     *
     * @param date
     * @return Integer
     */
    public static Integer getWeekOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setMinimalDaysInFirstWeek(7);
        int number = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (number == 0) {
            return 7;
        }
        return number;
    }

    /**
     * 设置某日期时间
     *
     * @param date   日期
     * @param hour   时
     * @param minute 分
     * @param second 秒
     * @return date
     */
    public static Date setTime(Date date, int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        return calendar.getTime();
    }

    /**
     * 设置日期
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return Date
     */
    public static Date setDate(int year, int month, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        return calendar.getTime();
    }

    /**
     * time差
     *
     * @param before 日期
     * @param after  另一个日期
     * @return long
     */
    public static long diffTimes(Date before, Date after) {
        if (before == null || after == null) {
            throw new IllegalArgumentException("Two dates must not be null");
        }
        return after.getTime() - before.getTime();
    }

    /**
     * 获取日期的年
     *
     * @param date
     * @return int
     */
    public static int getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * date格式化，转为Date
     *
     * @param date
     * @param dateFormat
     * @return Date
     */
    public static Date getDate(Date date, String dateFormat) {
        return parseDate(formatDate(date, dateFormat));
    }

    /**
     * 获取某天所在周的第一天和最后一天
     *
     * @param date 日期
     * @return String
     */
    public static String getFirstAndLastOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        int diff = 0;
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            diff = -6;
        } else {
            diff = 2 - calendar.get(Calendar.DAY_OF_WEEK);
        }
        calendar.add(Calendar.DAY_OF_WEEK, diff);
        String weekStart = formatDate(calendar.getTime(), DateUtil.YYYY_MM_DD);
        calendar.add(Calendar.DAY_OF_WEEK, 6);
        String weekEnd = formatDate(calendar.getTime(), DateUtil.YYYY_MM_DD);
        return weekStart + FIRST_END_WEEK_SEPARATOR + weekEnd;
    }

    /**
     * 天数差
     *
     * @param before 日期
     * @param after  另一个日期
     * @return int
     */
    public static int diffDay(Date before, Date after) {
        return (int) (diffTimes(before, after) / (1000 * 60 * 60 * 24));
    }

    /**
     * 月差
     * @param before 日期
     * @param after  另一个日期
     * @return int
     */
    public static int diffMonth(Date before, Date after) {
        int monthActual =0;
        int year = diffYear(before, after);
        int monthVirtual = getDateOnePart(after, Calendar.MONTH) - getDateOnePart(before, Calendar.MONTH);
        monthActual = year * 12 + monthVirtual;
        if (getDateOnePart(after, Calendar.DATE) - getDateOnePart(before, Calendar.DATE) > 0) {
            monthActual += 1;
        }
        return monthActual;
    }

    /**
     * 年差
     *
     * @param before 日期
     * @param after  另一个日期
     * @return int
     */
    public static int diffYear(Date before, Date after) {
        return getDateOnePart(after, Calendar.YEAR) - getDateOnePart(before, Calendar.YEAR);
    }

    /**
     * 获取日期中的某个值
     * （年YEAR、月MONTH、日DATE、时HOUR、分MINUTE、秒SECOND、星期DAY_OF_WEEK、
     * 该月第几天DAY_OF_MONTH、该月第几周DAY_OF_WEEK_IN_MONTH、该年第几周WEEK_OF_YEAR、该年第几天DAY_OF_YEAR）
     * 获取月份需加一，获取星期需减一
     *
     * @param date          日期
     * @param calendarField 获取部分的Calendar值
     * @return int
     */
    public static int getDateOnePart(Date date, int calendarField) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int result = calendar.get(calendarField);
        switch (calendarField) {
            case Calendar.MONTH:
                result += 1;
                break;
            case Calendar.DAY_OF_WEEK:
                result -= 1;
                break;
            default:
        }
        return result;
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static Long nowTime() {
        // 获取当前时间转成时间戳
        Date date = new Date();
        Timestamp ts = new Timestamp(date.getTime());
        Long createTime = ts.getTime();
        return createTime;
    }


    public static String getTimeString(Long timestamp, String dateFormat) {
        SimpleDateFormat format = new SimpleDateFormat(dateFormat,Locale.CHINESE);
        String timeString = format.format(timestamp);
        return timeString;
    }
     
    public static String getAmOrPmTime(Long timestamp, String dateFormat) {
        SimpleDateFormat format = new SimpleDateFormat(dateFormat);
        String timeString = format.format(timestamp);
        GregorianCalendar ca = new GregorianCalendar();
        ca.setTimeInMillis(timestamp);
        int type = ca.get(GregorianCalendar.AM_PM);
        if (type == 0) {
            timeString = "上午" + timeString;
        } else {
            timeString = "下午" + timeString;
        }

        return timeString;
    }
    
    public static String getAmOrPm(Long timestamp) {
        String timeString = "";
        GregorianCalendar ca = new GregorianCalendar();
        ca.setTimeInMillis(timestamp);
        int type = ca.get(GregorianCalendar.AM_PM);
        if (type == 0) {
            timeString = "上午";
        } else {
            timeString = "下午";
        }

        return timeString;
    }

    public static String getTimeDifference(Long one, Long two) {
        StringBuilder show = new StringBuilder();
        long day = 0;
        long hour = 0;
        long min = 0;
        long diff;
        if (one < two) {
            diff = two - one;
        } else {
            diff = one - two;
        }
        day = diff / (24 * 60 * 60 * 1000);
        if (day > 0) {
            show.append(day).append("天");
        }
        hour = (diff / (60 * 60 * 1000) - day * 24);
        if (hour > 0) {
            show.append(hour).append("小时");
        }
        min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
        if (min > 0) {
            show.append(min).append("分钟");
        }

        return show.toString();
    }
    
    
    /**
     * 日期加减计算
     * days > 0 加
     * days < 0 减
     */
    public static Date dayCalculation(Date date,int days) {
    	 Calendar rightNow = Calendar.getInstance();
    	 rightNow.setTime(date); 
    	//日期加10天
         rightNow.add(Calendar.DAY_OF_YEAR,days);
         Date newDate=rightNow.getTime();
         return newDate;
    }
    
    /**
     * 获取一个时间列表
     * @param date 初始时间点
     * @param days days > 0 加;days < 0 减
     * @return
     */
    public static List<String> getDateList(Date date,int days){
    	Date before = null;
    	Date after = null;
    	List<String> dateList = new ArrayList<String>();
    	if(days > 0) {
    		before = date;
    		after = dayCalculation(date, days);
    	}else {
    		before = dayCalculation(date, days);
    		after = date;
    	}
    	// 日期差
    	int n = diffDay(before,after);
    	for(int i = 0; i<=n;i++) {
    		Date day = dayCalculation(before, i);
    		dateList.add(DateUtil.formatDate(day, YYYY_MM_DD));
    	}
    	return dateList;
    }
    
    /**
     * 获取一个时间列表
     * @param before 初始时间点
     * @param after days > 0 加;days < 0 减
     * @return
     */
    public static List<String> getDateList(Date before,Date after){
    	List<String> dateList = new ArrayList<String>();
    	// 日期差
    	int n = diffDay(before,after);
    	for(int i = 0; i<=n;i++) {
    		Date day = dayCalculation(before, i);
    		dateList.add(DateUtil.formatDate(day, YYYY_MM_DD));
    	}
    	return dateList;
    }
    
    
    
    /**
     * 一周前
     * @return
     */
    public static Date getDayBeforeWeek(Date day) {
    	//一周前
    	Calendar c = Calendar.getInstance();
    	c.setTime(day);
        c.add(Calendar.DATE, - 6);
        Date beforeDay = c.getTime();
        return beforeDay;
    }
  
    /**
     * 一月前
     * @return
     */
    public static Date getDayBeforeMonth(Date day) {
    	//一月前
    	Calendar c = Calendar.getInstance();
    	c.setTime(day);
        c.add(Calendar.MONTH, -1);
        return c.getTime();
    }
    
    /**
     * 一年前
     * @return
     */
    public static Date getDayBeforeYear(Date day) {
    	//一年前
    	Calendar c = Calendar.getInstance();
    	c.setTime(day);
        c.add(Calendar.YEAR, -1);
        return c.getTime();
    }

    public static Timestamp getCurrentTimestamp(){
        return new Timestamp(Instant.now().toEpochMilli());
    }
}
